<route lang="json5">
	{
	style: {
	navigationStyle: 'custom',
	navigationBarTitleText: '脑波',
	enablePullDownRefresh: false,
	},
	}
</route>
<template>
	<view class="page">
		<wd-navbar title="脑波" :bordered="false">
			<template #right>
				<wd-icon name="setting" size="20px" color="white" @click="toConfig"></wd-icon>
			</template>
		</wd-navbar>
		<view class="echarts" style="background:red">
			<echarts :option="option" style="height: 300px"></echarts>
		</view>
		<view style="padding:30rpx;text-align:center">
			<view style="font-weight:bold;font-size:36rpx;">连接您的设备</view>
			<view style="font-size:26rpx;color:#333;margin:30rpx 0;">
				<view>打开蓝牙，点击连接，选择您的脑波设备进行连接</view>
				<view>当前蓝牙已打开</view>
			</view>
			<thButton type="primary" size="large" @click="showDeviceList" >连接<text class="iconfont icon-blue" ></text></thButton>
		</view>
		<view class="device">
			<view class="tip">
				<text class="ok" v-if="setting.currentBrain">
					{{setting.currentBrain.name}}
				</text>
				<text class="no" v-else>
					请连接设备
				</text>
			</view>
			<view>
				<text v-if="!setting.currentBrain" @click="showDeviceList" class="iconfont icon-blue"
					:class="[setting.currentBrain?'on':'']">连接</text>
				<text v-else class="iconfont icon-qiehuan" @click="deviceVisible = true"></text>
			</view>

		</view>
		<th-dialog title="请选择设备" v-model:visible="deviceVisible">
			<template v-slot:content>
				<view class="device-list">
					<view v-for="d in setting.brainDevices" :key="d.deviceId" class="card"
						:class="[setting.currentBrain && d.deviceId === setting.currentBrain.deviceId?'on':'']"
						@click="connectBluetooth(d.deviceId)">
						<view class="name">{{d.name}}</view>
						<view v-if="setting.currentBrain && d.deviceId === setting.currentBrain.deviceId">
							已连接
						</view>
					</view>
				</view>
				<view v-if="!isAvailable" class="find">蓝牙未打开</view>
				<view v-if="isAvailable && isDiscovery" class="find">正在搜索设备···</view>
			</template>
		</th-dialog>
	</view>

</template>

<script setup lang="ts">
	import { ab2hex, transformToArr, hexToDec } from './func'
	import echarts from '@/components/echarts.vue';
	import ThDialog from '@/pages/pm/assay-report/component/th-dialog.vue';
	import thButton from '@/pages/pm/assay-report/component/th-button.vue';
	import { voiceList } from '@/service/brain';
	import showModal from '@/utils/modal';

	import { useSetting } from '@/stores/setting';
	const setting = useSetting();

	const toConfig = () => {
		uni.navigateTo({
			url: '/pages/brainwave/config'
		})
	}

	/**
	 * 声音播放
	 * 
	**/
	const innerAudioContext = uni.createInnerAudioContext();
	innerAudioContext.loop = true;
	const voiceListData = ref([]);

	voiceList().then(res => {
		if (res.code === 0) {
			voiceListData.value = res.data.ruleList;
		}
	})

	let changeUrl = '';
	const playVoice = (value : number) => {
		const matchVoice = voiceListData.value.find(item => value > item.min && value <= item.max);
		changeUrl = matchVoice?.voiceUrl;

		if (changeUrl && innerAudioContext.src !== changeUrl) {
			innerAudioContext.stop();
			innerAudioContext.src = changeUrl;
			innerAudioContext.play();
		}
	}

	/**
	 * 脑波图
	 * 
	**/

	let data = [];
	let now = new Date(1997, 9, 3);
	let oneDay = 24 * 3600 * 1000;
	let value = Math.random() * 1000;

	function randomData() {
		now = new Date(+now + oneDay);
		value = value + Math.random() * 21 - 10;
		return {
			name: now.toString(),
			value: [
				[now.getFullYear(), now.getMonth() + 1, now.getDate()].join('/'),
				0
			]
		};
	}

	for (var i = 0; i < 60; i++) {
		data.push(randomData());
	}

	const option = ref({
		id: 'wave001',
		title: {
			text: '脑波图',
			textStyle: {
				fontSize: 16
			}
		},
		grid: {
			show: false,
			right: 10,
			bottom: 10
		},
		xAxis: {
			type: 'time',
			show: false
		},
		yAxis: {
			name: '单位：万',
			type: 'value',
			// max: 30,
			min: 0
		},
		series: [
			{
				data,
				type: 'line',
				symbol: 'none',
				smooth: true,
				lineStyle: {
					width: 1,
					color: "#000"
				}
			}
		]
	});

	// #ifdef APP-PLUS

	/***
		蓝牙是否打开可用 isBlueOpen
		是否正在搜索设备 isDiscovery
		设备是否连接
		特征是否可用
	**/

	const deviceVisible = ref(false);
	const currentBrain = ref();
	const isAvailable = ref(false);
	const isDiscovery = ref(false);

	// 初始化蓝牙
	const openBluetooth = () => {
		uni.openBluetoothAdapter({
			success: (e) => {
				//监听寻找到新设备的事件
				setting.onBrainDevices();
				if (e.errMsg == "openBluetoothAdapter:ok") {
					uni.getBluetoothAdapterState({
						success: function (res) {
							if (res.available) {
								//开始搜寻附近的蓝牙外围设备
								uni.startBluetoothDevicesDiscovery();
								isAvailable.value = true;
								isDiscovery.value = true;
							} else {
								uni.showToast({
									title: '本机蓝牙不可用',
									icon: 'none',
								});
								isAvailable.value = false;
							}
						},
					})
				}
			},
			fail: (err) => {
				uni.showModal({
					title: "提示",
					content: "请您打开蓝牙或检查微信是否授权蓝牙",
					showCancel: false,
				});
				isAvailable.value = false;
			}
		});
	}
	
	uni.onBluetoothAdapterStateChange((res) => {
		if (!res.available) {
			// uni.stopBluetoothDevicesDiscovery()
			isAvailable.value = false;
		} else {
			console.log(isAvailable.value);
			if(!isAvailable.value){
				openBluetooth();
			}
		}
	});

	// 监听设备断开
	uni.onBLEConnectionStateChange((res) => {
		if (!res.connected) {
			uni.closeBLEConnection({
				deviceId: res.deviceId,
				success() {
					if(res.deviceId === setting.currentBrain.deviceId){
						setting.currentBrain = null;
					}
					innerAudioContext?.stop();
				}
			})
		}
	});


	// 显示设备列表
	const showDeviceList = () => {
		if (!isAvailable.value) {
			uni.showToast({
				title: "请打开蓝牙",
				icon: 'none'
			});
		} else {
			deviceVisible.value = true;
		}
	}
	

	 
	 // 清空数据
	 const clearEchart = ()=>{
		 data = []
		 for (var i = 0; i < 60; i++) {
		 	data.push(randomData());
		 }
		 
		 option.value.series[0].data = data;
	 }
	 

	// 连接蓝牙
	const connectBluetooth = async (deviceId:string) => {
		if(setting.currentBrain) {
			// 阻止重复连接
			if(setting.currentBrain.deviceId === deviceId) return;
			// 切换设备前先断开当前设备
			await breakConnect(setting.currentBrain.deviceId);
			clearEchart();
			setting.currentBrain = null;
		};
		
		uni.showLoading({
			title: "正在连接",
			mask: true
		});
		//连接蓝牙
		uni.createBLEConnection({
			deviceId,
			timeout: 6000,
			success: async () => {
				// 获取设备所有服务
				const services = await getBLEServices(deviceId);
				// 查找所有特征值，增加到设备上
				await addCharacteristics(deviceId, services as [])
                
				// 找到能使用的特征值
				const device = setting.brainDevices.find((d) => d.deviceId === deviceId);
				const characteristic = device.characteristics.filter(s => s.read)[0] || device.characteristics[0];
                
				// 监听
				const isNotify = await notify(characteristic,true);
				
                if(isNotify){
					uni.hideLoading();
					setting.currentBrain = {
						...device,
						characteristicId:characteristic.characteristicId
					};
					deviceVisible.value = false;
					
					if (!setting.isNotify) {
						notifyChange();
					}
				}

			},
			fail(err) {
				uni.hideLoading();
				uni.showToast({
					title: '连接失败,请重试',
					icon: 'none'
				})
			}
		});
	}
	
	// 断开连接
	 const breakConnect = (deviceId:string)=>{
		 return new Promise((resolve) => {
		 	uni.closeBLEConnection({
		 		deviceId,
		 	 	success() {
		 			resolve(true)
		 		},
				fail(){
					resolve(false)
				}
		 	})
		 })
	 }
	 

	// 获取所有服务
	const getBLEServices = (deviceId : string) => {
		const getBLEDeviceServices = (resolve) => {
			uni.getBLEDeviceServices({
				deviceId,
				complete(res) {
					if (res.errMsg === "getBLEDeviceServices:ok" && res.services.length) {
						resolve(res.services)
					} else {
						getBLEDeviceServices(resolve)
					}
				}
			})
		}
		return new Promise((resolve) => {
			getBLEDeviceServices(resolve)
		})
	}

	// 补充所有服务的特征值
	const addCharacteristics = (deviceId : string, services : []) => {
		return new Promise(async (resolve) => {
			let characteristics = []
			for (var s = 0; s < services.length; s++) {
				const serviceId = services[s].uuid;
				const newCharacteristics = await getBLEDeviceCharacteristics({ deviceId, serviceId }) as [];
				characteristics = [...characteristics, ...newCharacteristics]
			}
			if (characteristics.length) {
				for (var index in setting.brainDevices) {
					if (setting.brainDevices[index].deviceId == deviceId) {
						setting.brainDevices[index].services = services;
						setting.brainDevices[index].characteristics = characteristics;
						break;
					}
				}
			}
			resolve(true)
		})
	}


	const getBLEDeviceCharacteristics = (param : any) => {
		return new Promise((resolve) => {
			uni.getBLEDeviceCharacteristics({
				...param,
				success(res) {
					const characteristics = res.characteristics.filter((c) => c.properties.notify).map((c) => {
						return {
							deviceId: param.deviceId,
							serviceId: param.serviceId,
							characteristicId: c.uuid,
							read: c.properties.read
						};
					})
					resolve(characteristics);
				},
				fail() {
					resolve(null);
				},
			});
		});
	};


	const notify = (param,state:boolean) => {
		return new Promise((resolve) => {
			uni.notifyBLECharacteristicValueChange({
				state, // 启用 notify 功能
				...param,
				success() {
					resolve(true)
				},
				fail(err) {
					resolve(false)
				}
			})
		})
	}

	

	const notifyChange = () => {
		let text : string;
		setting.isNotify = true;
		/* 监听低功耗蓝牙设备的特征值变化 */
		uni.onBLECharacteristicValueChange((CALLBACK) => {
			if(CALLBACK.characteristicId !== setting.currentBrain?.characteristicId) return;
			text += ab2hex(CALLBACK.value)
			if (/aaaa2002\w{2}8318/.test(text)) {
				const valueStr = text.substr(text.search(/aaaa2002\w{2}8318/), 72);
				if (valueStr.length === 72) {
					text = ''
					const [a1, a2, a3, b1, b2, b3] = transformToArr(valueStr);
					const total = hexToDec(a1) * 65536 + hexToDec(a2) * 256 + hexToDec(a3) + hexToDec(b1) * 65536 + hexToDec(b2) * 256 + hexToDec(b3);
					if (!isNaN(total)) {
					   uni.$emit('notify',total)
					}
				}
			}
		})
	}

	onMounted(() => {
		// 初始化蓝牙
		openBluetooth();
		uni.$off('notify');
		uni.$on('notify',(total)=>{
			now = new Date(+now + oneDay);
			option.value.series[0].data.shift();
			option.value.series[0].data.push({
				name: now.toString(),
				value: [[now.getFullYear(), now.getMonth() + 1, now.getDate()].join('/'), total / 10000]
			});
			playVoice(total);
		})
	})
	// #endif

	const canBack = ref(false)

	onBackPress(() => {
		if (canBack.value) return false;
		showModal({
			title: '提示',
			content: '设备正在连接中，确定要退出吗？',
			showCancel: true,
			confirm: async() => {
				canBack.value = true;
				if (setting.currentBrain) {					
					innerAudioContext.destroy();
					console.log(setting.currentBrain.deviceId)
					await breakConnect(setting.currentBrain?.deviceId)
					uni.navigateBack({
						delta: 1
					})
				} else {
					uni.navigateBack({
						delta: 1
					})
				}
			},
		});
		return true;
	})
</script>

<style lang="scss" scoped>
	@import url('@/static/iconfont/iconfont.css');

	.page {
		// margin: 0 15rpx;
	}

	.device-list {
		padding: 0 20rpx;
		max-height: 700rpx;
		overflow-y: auto;

		.card {
			padding: 20rpx;
			display: flex;
			align-items: center;
			border-radius: 8rpx;
			box-shadow: 0 0 10rpx 0 #e6e6e6;
			margin: 20rpx 0;
			justify-content: space-between;
			color: #333;

			&.on {
				color: #1890ff;
			}

			.name {
				font-weight: bold;
				padding-left: 80rpx;
				height: 60rpx;
				line-height: 60rpx;
				background: url(@/static/blue.png) no-repeat;
				background-size: 60rpx 60rpx;
				font-size: 36rpx;

			}
		}
	}

	.echarts {
		// margin: 15rpx 0;
		// box-shadow: 0 0 10rpx 0 #cdcdcd;
		// border-radius: 15rpx;
	}

	.device {
		margin: 15rpx;
		padding: 30rpx 15rpx;
		box-shadow: 0 0 10rpx 0 #cdcdcd;
		border-radius: 10rpx;
		display: flex;
		justify-content: space-between;
		align-items: center;

		.icon-qiehuan,
		.icon-blue {
			font-weight: bold;
			color: #8a8a8a;
			margin-right: 15rpx;
		}

		.icon-qiehuan,
		.icon-blue.on {
			color: #1890ff;
		}
	}

	.find {
		text-align: center;
		padding: 30rpx 0;
		color: #8a8a8a;
	}

	.tip {
		.ok {
			font-weight: bold;
		}

		.no {
			color: #8a8a8a;
		}
	}

	:deep(.wd-navbar__right--hover) {
		background: none;
	}
</style>